







  subroutine fiona_input_0d_i2(dataset_name, var_name, value, start, time_step, fatal)

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    integer(2), intent(out) :: value
    integer, intent(in), optional :: start(:)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    integer, allocatable :: start_opt(:)
    integer ierr, varid

    dataset => get_dataset(dataset_name)

    if (present(time_step)) then
      if (present(start)) then
        allocate(start_opt(size(start)+1)); start_opt(1:size(start)) = start; start_opt(size(start)+1) = time_step
      else
        allocate(start_opt(1)); start_opt(1) = time_step
      end if
    else
      if (present(start)) then
        allocate(start_opt(size(start))); start_opt = start
      else
        allocate(start_opt(1)); start_opt(1) = 1
      end if
    end if

    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_VAR(dataset%id, varid, value, start=start_opt)
      call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
    end if
#ifdef HAS_MPI
    if (dataset%group_mpi_comm /= MPI_COMM_NULL) then
      call MPI_BCAST(value, 1, MPI_SHORT, 0, dataset%group_mpi_comm, ierr)
    end if
#endif

    if (allocated(start_opt)) deallocate(start_opt)

  end subroutine fiona_input_0d_i2

  subroutine fiona_input_0d_i4(dataset_name, var_name, value, start, time_step, fatal)

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    integer(4), intent(out) :: value
    integer, intent(in), optional :: start(:)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    integer, allocatable :: start_opt(:)
    integer ierr, varid

    dataset => get_dataset(dataset_name)

    if (present(time_step)) then
      if (present(start)) then
        allocate(start_opt(size(start)+1)); start_opt(1:size(start)) = start; start_opt(size(start)+1) = time_step
      else
        allocate(start_opt(1)); start_opt(1) = time_step
      end if
    else
      if (present(start)) then
        allocate(start_opt(size(start))); start_opt = start
      else
        allocate(start_opt(1)); start_opt(1) = 1
      end if
    end if

    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_VAR(dataset%id, varid, value, start=start_opt)
      call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
    end if
#ifdef HAS_MPI
    if (dataset%group_mpi_comm /= MPI_COMM_NULL) then
      call MPI_BCAST(value, 1, MPI_INT, 0, dataset%group_mpi_comm, ierr)
    end if
#endif

    if (allocated(start_opt)) deallocate(start_opt)

  end subroutine fiona_input_0d_i4

  subroutine fiona_input_0d_r4(dataset_name, var_name, value, start, time_step, fatal)

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    real(4), intent(out) :: value
    integer, intent(in), optional :: start(:)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    integer, allocatable :: start_opt(:)
    integer ierr, varid

    dataset => get_dataset(dataset_name)

    if (present(time_step)) then
      if (present(start)) then
        allocate(start_opt(size(start)+1)); start_opt(1:size(start)) = start; start_opt(size(start)+1) = time_step
      else
        allocate(start_opt(1)); start_opt(1) = time_step
      end if
    else
      if (present(start)) then
        allocate(start_opt(size(start))); start_opt = start
      else
        allocate(start_opt(1)); start_opt(1) = 1
      end if
    end if

    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_VAR(dataset%id, varid, value, start=start_opt)
      call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
    end if
#ifdef HAS_MPI
    if (dataset%group_mpi_comm /= MPI_COMM_NULL) then
      call MPI_BCAST(value, 1, MPI_FLOAT, 0, dataset%group_mpi_comm, ierr)
    end if
#endif

    if (allocated(start_opt)) deallocate(start_opt)

  end subroutine fiona_input_0d_r4

  subroutine fiona_input_0d_r8(dataset_name, var_name, value, start, time_step, fatal)

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    real(8), intent(out) :: value
    integer, intent(in), optional :: start(:)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    integer, allocatable :: start_opt(:)
    integer ierr, varid

    dataset => get_dataset(dataset_name)

    if (present(time_step)) then
      if (present(start)) then
        allocate(start_opt(size(start)+1)); start_opt(1:size(start)) = start; start_opt(size(start)+1) = time_step
      else
        allocate(start_opt(1)); start_opt(1) = time_step
      end if
    else
      if (present(start)) then
        allocate(start_opt(size(start))); start_opt = start
      else
        allocate(start_opt(1)); start_opt(1) = 1
      end if
    end if

    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_VAR(dataset%id, varid, value, start=start_opt)
      call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
    end if
#ifdef HAS_MPI
    if (dataset%group_mpi_comm /= MPI_COMM_NULL) then
      call MPI_BCAST(value, 1, MPI_DOUBLE, 0, dataset%group_mpi_comm, ierr)
    end if
#endif

    if (allocated(start_opt)) deallocate(start_opt)

  end subroutine fiona_input_0d_r8

  subroutine fiona_input_1d_i2(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 1

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    integer(2), intent(out) :: array(:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i2(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i2(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%i2(buffer%is:buffer%ie) = scale_factor * buffer%i2(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i1 = 1, size(array, 1)
array(i1 ) = buffer%i2(ibuf)
ibuf = ibuf + 1
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%i2(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_SHORT, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_SHORT, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_1d_i2

  subroutine fiona_input_1d_i4(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 1

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    integer(4), intent(out) :: array(:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i4(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i4(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%i4(buffer%is:buffer%ie) = scale_factor * buffer%i4(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i1 = 1, size(array, 1)
array(i1 ) = buffer%i4(ibuf)
ibuf = ibuf + 1
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%i4(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_INT, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_INT, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_1d_i4

  subroutine fiona_input_1d_r4(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 1

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    real(4), intent(out) :: array(:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r4(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r4(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%r4(buffer%is:buffer%ie) = scale_factor * buffer%r4(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i1 = 1, size(array, 1)
array(i1 ) = buffer%r4(ibuf)
ibuf = ibuf + 1
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%r4(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_FLOAT, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_FLOAT, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_1d_r4

  subroutine fiona_input_1d_r8(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 1

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    real(8), intent(out) :: array(:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r8(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r8(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%r8(buffer%is:buffer%ie) = scale_factor * buffer%r8(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i1 = 1, size(array, 1)
array(i1 ) = buffer%r8(ibuf)
ibuf = ibuf + 1
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%r8(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_DOUBLE, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_DOUBLE, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_1d_r8

  subroutine fiona_input_2d_i2(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 2

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    integer(2), intent(out) :: array(:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i2(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i2(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%i2(buffer%is:buffer%ie) = scale_factor * buffer%i2(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ) = buffer%i2(ibuf)
ibuf = ibuf + 1
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%i2(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_SHORT, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_SHORT, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_2d_i2

  subroutine fiona_input_2d_i4(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 2

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    integer(4), intent(out) :: array(:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i4(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i4(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%i4(buffer%is:buffer%ie) = scale_factor * buffer%i4(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ) = buffer%i4(ibuf)
ibuf = ibuf + 1
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%i4(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_INT, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_INT, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_2d_i4

  subroutine fiona_input_2d_r4(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 2

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    real(4), intent(out) :: array(:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r4(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r4(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%r4(buffer%is:buffer%ie) = scale_factor * buffer%r4(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ) = buffer%r4(ibuf)
ibuf = ibuf + 1
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%r4(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_FLOAT, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_FLOAT, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_2d_r4

  subroutine fiona_input_2d_r8(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 2

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    real(8), intent(out) :: array(:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r8(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r8(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%r8(buffer%is:buffer%ie) = scale_factor * buffer%r8(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ) = buffer%r8(ibuf)
ibuf = ibuf + 1
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%r8(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_DOUBLE, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_DOUBLE, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_2d_r8

  subroutine fiona_input_3d_i2(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 3

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    integer(2), intent(out) :: array(:,:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 ,i3 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i2(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i2(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%i2(buffer%is:buffer%ie) = scale_factor * buffer%i2(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i3 = 1, size(array, 3)
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ,i3 ) = buffer%i2(ibuf)
ibuf = ibuf + 1
end do
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%i2(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_SHORT, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_SHORT, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_3d_i2

  subroutine fiona_input_3d_i4(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 3

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    integer(4), intent(out) :: array(:,:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 ,i3 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i4(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i4(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%i4(buffer%is:buffer%ie) = scale_factor * buffer%i4(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i3 = 1, size(array, 3)
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ,i3 ) = buffer%i4(ibuf)
ibuf = ibuf + 1
end do
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%i4(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_INT, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_INT, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_3d_i4

  subroutine fiona_input_3d_r4(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 3

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    real(4), intent(out) :: array(:,:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 ,i3 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r4(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r4(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%r4(buffer%is:buffer%ie) = scale_factor * buffer%r4(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i3 = 1, size(array, 3)
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ,i3 ) = buffer%r4(ibuf)
ibuf = ibuf + 1
end do
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%r4(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_FLOAT, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_FLOAT, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_3d_r4

  subroutine fiona_input_3d_r8(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 3

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    real(8), intent(out) :: array(:,:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 ,i3 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r8(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r8(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%r8(buffer%is:buffer%ie) = scale_factor * buffer%r8(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i3 = 1, size(array, 3)
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ,i3 ) = buffer%r8(ibuf)
ibuf = ibuf + 1
end do
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%r8(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_DOUBLE, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_DOUBLE, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_3d_r8

  subroutine fiona_input_4d_i2(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 4

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    integer(2), intent(out) :: array(:,:,:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 ,i3 ,i4 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1,1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i2(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i2(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%i2(buffer%is:buffer%ie) = scale_factor * buffer%i2(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i4 = 1, size(array, 4)
do i3 = 1, size(array, 3)
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ,i3 ,i4 ) = buffer%i2(ibuf)
ibuf = ibuf + 1
end do
end do
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%i2(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_SHORT, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_SHORT, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_4d_i2

  subroutine fiona_input_4d_i4(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 4

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    integer(4), intent(out) :: array(:,:,:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 ,i3 ,i4 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1,1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i4(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i4(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%i4(buffer%is:buffer%ie) = scale_factor * buffer%i4(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i4 = 1, size(array, 4)
do i3 = 1, size(array, 3)
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ,i3 ,i4 ) = buffer%i4(ibuf)
ibuf = ibuf + 1
end do
end do
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%i4(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_INT, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_INT, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_4d_i4

  subroutine fiona_input_4d_r4(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 4

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    real(4), intent(out) :: array(:,:,:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 ,i3 ,i4 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1,1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r4(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r4(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%r4(buffer%is:buffer%ie) = scale_factor * buffer%r4(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i4 = 1, size(array, 4)
do i3 = 1, size(array, 3)
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ,i3 ,i4 ) = buffer%r4(ibuf)
ibuf = ibuf + 1
end do
end do
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%r4(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_FLOAT, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_FLOAT, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_4d_r4

  subroutine fiona_input_4d_r8(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 4

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    real(8), intent(out) :: array(:,:,:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 ,i3 ,i4 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1,1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r8(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r8(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%r8(buffer%is:buffer%ie) = scale_factor * buffer%r8(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i4 = 1, size(array, 4)
do i3 = 1, size(array, 3)
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ,i3 ,i4 ) = buffer%r8(ibuf)
ibuf = ibuf + 1
end do
end do
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%r8(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_DOUBLE, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_DOUBLE, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_4d_r8

  subroutine fiona_input_5d_i2(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 5

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    integer(2), intent(out) :: array(:,:,:,:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 ,i3 ,i4 ,i5 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1,1,1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i2(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i2(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%i2(buffer%is:buffer%ie) = scale_factor * buffer%i2(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i5 = 1, size(array, 5)
do i4 = 1, size(array, 4)
do i3 = 1, size(array, 3)
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ,i3 ,i4 ,i5 ) = buffer%i2(ibuf)
ibuf = ibuf + 1
end do
end do
end do
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%i2(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_SHORT, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_SHORT, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_5d_i2

  subroutine fiona_input_5d_i4(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 5

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    integer(4), intent(out) :: array(:,:,:,:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 ,i3 ,i4 ,i5 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1,1,1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i4(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i4(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%i4(buffer%is:buffer%ie) = scale_factor * buffer%i4(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i5 = 1, size(array, 5)
do i4 = 1, size(array, 4)
do i3 = 1, size(array, 3)
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ,i3 ,i4 ,i5 ) = buffer%i4(ibuf)
ibuf = ibuf + 1
end do
end do
end do
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%i4(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_INT, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_INT, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_5d_i4

  subroutine fiona_input_5d_r4(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 5

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    real(4), intent(out) :: array(:,:,:,:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 ,i3 ,i4 ,i5 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1,1,1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r4(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r4(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%r4(buffer%is:buffer%ie) = scale_factor * buffer%r4(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i5 = 1, size(array, 5)
do i4 = 1, size(array, 4)
do i3 = 1, size(array, 3)
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ,i3 ,i4 ,i5 ) = buffer%r4(ibuf)
ibuf = ibuf + 1
end do
end do
end do
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%r4(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_FLOAT, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_FLOAT, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_5d_r4

  subroutine fiona_input_5d_r8(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 5

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    real(8), intent(out) :: array(:,:,:,:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 ,i3 ,i4 ,i5 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1,1,1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r8(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r8(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%r8(buffer%is:buffer%ie) = scale_factor * buffer%r8(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i5 = 1, size(array, 5)
do i4 = 1, size(array, 4)
do i3 = 1, size(array, 3)
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ,i3 ,i4 ,i5 ) = buffer%r8(ibuf)
ibuf = ibuf + 1
end do
end do
end do
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%r8(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_DOUBLE, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_DOUBLE, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_5d_r8

  subroutine fiona_input_6d_i2(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 6

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    integer(2), intent(out) :: array(:,:,:,:,:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 ,i3 ,i4 ,i5 ,i6 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1,1,1,1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i2(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i2(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%i2(buffer%is:buffer%ie) = scale_factor * buffer%i2(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i6 = 1, size(array, 6)
do i5 = 1, size(array, 5)
do i4 = 1, size(array, 4)
do i3 = 1, size(array, 3)
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ,i3 ,i4 ,i5 ,i6 ) = buffer%i2(ibuf)
ibuf = ibuf + 1
end do
end do
end do
end do
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%i2(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_SHORT, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_SHORT, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_6d_i2

  subroutine fiona_input_6d_i4(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 6

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    integer(4), intent(out) :: array(:,:,:,:,:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 ,i3 ,i4 ,i5 ,i6 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1,1,1,1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i4(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i4(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%i4(buffer%is:buffer%ie) = scale_factor * buffer%i4(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i6 = 1, size(array, 6)
do i5 = 1, size(array, 5)
do i4 = 1, size(array, 4)
do i3 = 1, size(array, 3)
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ,i3 ,i4 ,i5 ,i6 ) = buffer%i4(ibuf)
ibuf = ibuf + 1
end do
end do
end do
end do
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%i4(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_INT, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_INT, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_6d_i4

  subroutine fiona_input_6d_r4(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 6

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    real(4), intent(out) :: array(:,:,:,:,:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 ,i3 ,i4 ,i5 ,i6 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1,1,1,1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r4(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r4(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%r4(buffer%is:buffer%ie) = scale_factor * buffer%r4(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i6 = 1, size(array, 6)
do i5 = 1, size(array, 5)
do i4 = 1, size(array, 4)
do i3 = 1, size(array, 3)
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ,i3 ,i4 ,i5 ,i6 ) = buffer%r4(ibuf)
ibuf = ibuf + 1
end do
end do
end do
end do
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%r4(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_FLOAT, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_FLOAT, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_6d_r4

  subroutine fiona_input_6d_r8(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 6

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    real(8), intent(out) :: array(:,:,:,:,:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 ,i3 ,i4 ,i5 ,i6 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1,1,1,1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r8(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r8(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%r8(buffer%is:buffer%ie) = scale_factor * buffer%r8(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i6 = 1, size(array, 6)
do i5 = 1, size(array, 5)
do i4 = 1, size(array, 4)
do i3 = 1, size(array, 3)
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ,i3 ,i4 ,i5 ,i6 ) = buffer%r8(ibuf)
ibuf = ibuf + 1
end do
end do
end do
end do
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%r8(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_DOUBLE, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_DOUBLE, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_6d_r8

  subroutine fiona_input_7d_i2(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 7

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    integer(2), intent(out) :: array(:,:,:,:,:,:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 ,i3 ,i4 ,i5 ,i6 ,i7 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1,1,1,1,1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i2(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i2(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%i2(buffer%is:buffer%ie) = scale_factor * buffer%i2(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i7 = 1, size(array, 7)
do i6 = 1, size(array, 6)
do i5 = 1, size(array, 5)
do i4 = 1, size(array, 4)
do i3 = 1, size(array, 3)
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ,i3 ,i4 ,i5 ,i6 ,i7 ) = buffer%i2(ibuf)
ibuf = ibuf + 1
end do
end do
end do
end do
end do
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%i2(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_SHORT, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_SHORT, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_7d_i2

  subroutine fiona_input_7d_i4(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 7

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    integer(4), intent(out) :: array(:,:,:,:,:,:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 ,i3 ,i4 ,i5 ,i6 ,i7 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1,1,1,1,1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i4(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%i4(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%i4(buffer%is:buffer%ie) = scale_factor * buffer%i4(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i7 = 1, size(array, 7)
do i6 = 1, size(array, 6)
do i5 = 1, size(array, 5)
do i4 = 1, size(array, 4)
do i3 = 1, size(array, 3)
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ,i3 ,i4 ,i5 ,i6 ,i7 ) = buffer%i4(ibuf)
ibuf = ibuf + 1
end do
end do
end do
end do
end do
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%i4(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_INT, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_INT, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_7d_i4

  subroutine fiona_input_7d_r4(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 7

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    real(4), intent(out) :: array(:,:,:,:,:,:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 ,i3 ,i4 ,i5 ,i6 ,i7 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1,1,1,1,1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r4(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r4(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%r4(buffer%is:buffer%ie) = scale_factor * buffer%r4(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i7 = 1, size(array, 7)
do i6 = 1, size(array, 6)
do i5 = 1, size(array, 5)
do i4 = 1, size(array, 4)
do i3 = 1, size(array, 3)
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ,i3 ,i4 ,i5 ,i6 ,i7 ) = buffer%r4(ibuf)
ibuf = ibuf + 1
end do
end do
end do
end do
end do
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%r4(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_FLOAT, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_FLOAT, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_7d_r4

  subroutine fiona_input_7d_r8(dataset_name, var_name, array, start, count, time_step, fatal)

    integer, parameter :: n = 7

    character(*), intent(in) :: dataset_name
    character(*), intent(in) :: var_name
    real(8), intent(out) :: array(:,:,:,:,:,:,:)
    integer, intent(in), optional :: start(n)
    integer, intent(in), optional :: count(n)
    integer, intent(in), optional :: time_step
    logical, intent(in), optional :: fatal

    type(dataset_type), pointer :: dataset
    type(var_type), pointer :: var
    type(buffer_type) buffer
    real(8) add_offset, scale_factor
    logical fatal_opt, use_add_offset_and_scale_factor
    integer i, ierr, varid
    integer ibuf, i1 ,i2 ,i3 ,i4 ,i5 ,i6 ,i7 

    ! All count should be greater than zero!
    if (present(count)) then
      if (any(count <= 0)) then
        call log_error("Variable " // trim(var_name) // " dimension is problematic!")
      end if
    end if

    fatal_opt = .false.; if (present(fatal)) fatal_opt = fatal

    dataset => get_dataset(dataset_name)
    var => dataset%get_var(var_name)
    call gather_start_count(dataset, n, shape(array), start, count)
    if (dataset%is_group_root) then
      ierr = NF90_INQ_VARID(dataset%id, var_name, varid)
      call handle_error(ierr, "No variable """ // trim(var_name) // """ in dataset """ // &
                        trim(dataset%file_path) // """!", __FILE__, __LINE__)
      ierr = NF90_GET_ATT(dataset%id, varid, "add_offset", add_offset)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      ierr = NF90_GET_ATT(dataset%id, varid, "scale_factor", scale_factor)
      use_add_offset_and_scale_factor = ierr == NF90_NOERR
      call buffer%init(buffer_size(dataset, n), array(1,1,1,1,1,1,1))
#ifdef HAS_MPI
      if (dataset%is_parallel) then
        ierr = NF90_VAR_PAR_ACCESS(dataset%id, varid, NF90_COLLECTIVE)
        call handle_error(ierr, "Failed to set parallel access for variable " // trim(var_name) // "!", __FILE__, __LINE__)
      end if
#endif
    end if
    do i = 1, dataset%group_nproc
      if (dataset%is_group_root .or. dataset%group_proc_id == i - 1) then
        if (dataset%is_group_root) then
          if (product(dataset%group_count(1:n,i)) > 0) then
            call buffer%shift_index(product(dataset%group_count(1:n,i)))
            if (present(time_step)) then
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r8(buffer%is:buffer%ie), &
                start=[dataset%group_start(1:n,i),time_step], &
                count=[dataset%group_count(1:n,i),1])
            else
              ierr = NF90_GET_VAR(dataset%id, varid, buffer%r8(buffer%is:buffer%ie), &
                start=dataset%group_start(1:n,i), &
                count=dataset%group_count(1:n,i))
            end if
            if (use_add_offset_and_scale_factor) then
              buffer%r8(buffer%is:buffer%ie) = scale_factor * buffer%r8(buffer%is:buffer%ie) + add_offset
            end if
          end if
          if (i == 1) then
            if (buffer%is > 0) then
            ibuf = buffer%is
do i7 = 1, size(array, 7)
do i6 = 1, size(array, 6)
do i5 = 1, size(array, 5)
do i4 = 1, size(array, 4)
do i3 = 1, size(array, 3)
do i2 = 1, size(array, 2)
do i1 = 1, size(array, 1)
array(i1 ,i2 ,i3 ,i4 ,i5 ,i6 ,i7 ) = buffer%r8(ibuf)
ibuf = ibuf + 1
end do
end do
end do
end do
end do
end do
end do

            end if
          else
#ifdef HAS_MPI
            call MPI_ISEND(buffer%r8(buffer%is:buffer%ie), buffer%ie-buffer%is+1, MPI_DOUBLE, i-1, 99, &
                           dataset%group_mpi_comm, dataset%group_send_req(i), ierr)
#endif
          end if
        else
#ifdef HAS_MPI
          call MPI_RECV(array, size(array), MPI_DOUBLE, 0, 99, dataset%group_mpi_comm, MPI_STATUS_IGNORE, ierr)
#endif
        end if
        if (fatal_opt) then
          call handle_error(ierr, "Failed to read variable """ // trim(var_name) // """ in dataset """ // &
                            trim(dataset%file_path) // """!", __FILE__, __LINE__)
        end if
      end if
    end do
    call dataset%wait_send()
    call buffer%clear()

  end subroutine fiona_input_7d_r8
